#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Time    : 2024/10/27 10:14
# @Author  : astock
# @File    : gen_ft.py
# @Software: PyCharm
import collections
import copy
import os
import re
import sys
import time
from queue import Queue
from venv import logger

import openpyxl
import pandas as pd
from openpyxl.reader.excel import load_workbook

from models.stock_model import StockNumber, DayInfo
from mylib import download_all
from mylib.mycsv import sort_csv
from send_email import send_email_xlsx, send_email_html_gen_down_up2
from update_sh import get_bkd_today

st_queue = Queue()

def analysis_stock(sn, p_break_days, today_date):
    """

    :param sn:
    :param p_break_days:
    :return:
    """
    sn_csv_path = f'stocks/{sn.ts_code}.csv'
    if not os.path.exists(os.path.abspath(sn_csv_path)):
        try:
            download_all.analysis_stock(sn)
        except Exception as e:
            return None, None
    df2 = pd.read_csv(sn_csv_path)
    stock_number_arr = sn.ts_code.split('.')
    stock_number = f'{stock_number_arr[1]}{stock_number_arr[0]}'
    link_addr = f'https://xueqiu.com/S/{stock_number}'
    date_arr = []
    N = 6  # N日最低
    for row2 in df2.index:
        d = DayInfo(sn, df2.loc[row2])
        if d.trade_date_str > str(today_date):
            continue
        if len(date_arr) > p_break_days:
            break
        if row2 + N > df2.shape[0]:
            break
        di_arr = [DayInfo(sn, df2.iloc[idx]) for idx in range(row2, row2 + N)]
        low_arr = [di.low for di in di_arr]
        # if (min(low_arr) in [low_arr[1], low_arr[0]]
        if (min(low_arr) in [low_arr[2], low_arr[1], low_arr[0]]
                and di_arr[0].pct_chg > 3):
            cha_pct = round((max(low_arr) - min(low_arr)) / min(low_arr), 2)
            date_arr.append(
                (str(di_arr[0].trade_date), cha_pct, sn.industry, sn.name, sn.ts_code, di_arr[0].close,
                 di_arr[0].pct_chg, link_addr))
    return date_arr, link_addr


def red_min_value(today_date, excel_path):
    rank_number = 0
    wb = load_workbook(excel_path)
    sheet = wb['Sheet1']
    # 标记最小值的背景色为红色
    color = False
    for row in sheet[2:sheet.max_row]:
        for cell in row:
            if not rank_number and cell.col_idx == 1:
                rank_number = cell.value
            if cell.col_idx == 1:
                if int(cell.value) <= 6:
                    color = True
                else:
                    color = False
            if color:
                cell.fill = openpyxl.styles.PatternFill(start_color='FF0000', end_color='FF0000', fill_type='solid')
    # 保存工作簿
    color_excel_file_path = f'{today_date}_output_gen_down_up2_color.xlsx'  # 加载Excel文件
    if os.path.exists(color_excel_file_path):
        os.remove(color_excel_file_path)
    wb.save(color_excel_file_path)
    return rank_number, color_excel_file_path


def csv2excel(full_path_csv):
    # csv转excel
    try:
        excel_path = str(full_path_csv).replace('.csv', '.xlsx')
        # 读取CSV文件
        df = pd.read_csv(full_path_csv)
        df_unique = df.drop_duplicates()
        df2 = df_unique.iloc[:, :5]
        # 将DataFrame写入Excel文件
        df2.to_csv(full_path_csv)
        df2.to_excel(excel_path, index=False)
        return excel_path
    except Exception as e:
        print(e)


def send_by_number(csv_path, today_date, today_arr, result_dict, indus_count_dict):
    # 获取上证涨跌幅度字典
    df_sh = pd.read_csv('shanghai_index.csv')
    df_sh_list = df_sh.to_dict(orient='records')
    sh_dict = {}
    for item in df_sh_list:
        trade_date = str(item.get('日期')).replace('-', '')
        sh_dict[trade_date] = item

    # todo 设置当日最大存储csv stock条数
    m = 50
    # 是否需要发邮件
    sort_result_dict = sorted(result_dict.items(), key=lambda x: len(x[1]), reverse=True)
    date_indus_count = collections.defaultdict(dict)
    for date_list in sort_result_dict:
        indus_count = collections.defaultdict(list)
        for item in date_list[1]:
            indus_count[item[2]].append(item)
        date_indus_count[date_list[0]] = indus_count

    cnt = 0
    with open(csv_path, 'w') as fw:
        for k, v in sort_result_dict:
            k = str(int(eval(k)))
            indus_pct_dict = collections.defaultdict(list)
            k_indus_cunt_dict = date_indus_count.get(k)
            # max_pct = 0
            for indus, indus_stocks in k_indus_cunt_dict.items():
                indus_all = indus_count_dict.get(indus)
                indus_pct = round(len(indus_stocks) / indus_all, 2)
                # max_pct = max_pct if max_pct > indus_pct else indus_pct
                indus_pct_dict[(indus_pct, len(indus_stocks), indus_all)] = indus_stocks
            sort_indus_pct_dict = sorted(indus_pct_dict.items(), key=lambda x: x[0][0], reverse=True)
            cnt += 1
            if cnt == 1:
                title_arr = [str(i) for i in range(4 * m)]
                title_str = ','.join(title_arr)
                fw.write(f'排名,日期,总数,上证收盘,上证涨幅,{title_str}\n')
            vs = []
            for tp_indus_stocks in sort_indus_pct_dict:
                sort_tp_indus_stocks = sorted(tp_indus_stocks[1], key=lambda x: x[6], reverse=True)
                pct = tp_indus_stocks[0]
                for si_idx, si in enumerate(sort_tp_indus_stocks):
                    if si_idx > 4:
                        # todo 每个行业最多5支
                        break
                    si2 = list(si)
                    si2[2] = f'{pct[0]}-{si[2]}-{pct[1]}-{pct[2]}'
                    vs.append(si2)
                if len(vs) > m:
                    break
            vs2 = []
            for item in vs[:m]:
                vs2.append(str(item[2]))
                vs2.append(str(item[3]))
                vs2.append(str(item[6]))
                link_addr = f'=HYPERLINK("{item[7]}")'
                vs2.append(link_addr)
            vs2_str = ','.join(vs2)
            sh_di = int(sh_dict[k].get('收盘'))
            sh_zdf = sh_dict[k].get('涨跌幅')
            fw.write(f'{cnt},{k},{len(v)},{sh_di},{sh_zdf},{vs2_str}\n')
    sort_csv(csv_path, ['日期'], [False])
    try:
        df = pd.read_csv(csv_path)
        email_list = df.to_dict(orient='records')
        today_stocks = list(email_list[0].values())[5:]
    except Exception as e:
        logger.error(e)
        today_stocks = []
    # 发送图表excel邮件
    result_xlsx = csv2excel(csv_path)
    rank_number, color_result_xlsx = red_min_value(today_date, result_xlsx)
    email_title = f'{today_date}_gen_down_up2_【{rank_number}】-excel【{len(today_arr)}】支'
    send_email_xlsx.send_xlsx(email_title, color_result_xlsx)
    return rank_number, today_stocks


def send_by_date(csv_path, today_date, today_arr, rank_number):
    with open(csv_path, 'w') as fw:
        fw.write(f'索引,行业,名称,link_addr,涨跌幅\n')
        temp = []
        email_arr = []
        idx = 0
        for item in today_arr:
            if str(item) == 'nan':
                break
            temp.append(item)
            if len(temp) == 4:
                # 0.05-汽车整车-1-19,上汽集团,7.58,"=HYPERLINK(""https://xueqiu.com/S/SH600104"")"
                idx += 1
                temp2 = copy.deepcopy(temp)
                try:
                    temp2[3] = re.findall('"(.*?)"', temp2[3])[0]
                    fw.write(f'{idx},{temp2[0]},{temp2[1]},{temp2[2]},{temp2[3]}\n')
                    email_arr.append(temp2)
                    temp = []
                except Exception as e:
                    logger.error(e)
                    logger.error(temp2)
    time.sleep(10)
    email_title = f'{today_date}_gen_down_up2_【{rank_number}】-今【{len(email_arr)}】支'
    send_email_html_gen_down_up2.send_html(email_arr, email_title)


def get_all_stock(p_stocks, p_break_days=5, bkd=0):
    """

    :param p_stocks:
    :param p_break_days:
    :return:
    """
    today_date = get_bkd_today(bkd)
    df = pd.read_csv('all.csv')
    result_dict = collections.defaultdict(list)
    # 存储每个行业总数
    indus_count_dict = collections.defaultdict(int)
    for row in df.index:
        sn = StockNumber(df.loc[row])
        if p_stocks and sn.name not in p_stocks:
            continue
        if '退' in sn.name:
            continue
        if 'ST' in sn.name:
            continue
        if not str(sn.ts_code).startswith('60') \
                and not str(sn.ts_code).startswith('30') \
                and not str(sn.ts_code).startswith('00'):
            continue
        date_arr, link_addr = analysis_stock(sn, p_break_days, today_date)
        if date_arr is None or link_addr is None:
            continue
        date_arr.sort(reverse=True)
        msg = f'{sn.name},{sn.ts_code},{sn.industry}\n'
        indus_count_dict[sn.industry] += 1
        print(today_date, link_addr, row, msg)
        for d in date_arr:
            result_dict[d[0]].append(d)
    # 判断是否需要发邮件
    today_arr = result_dict.get(f'{today_date}')
    today_arr = [] if today_arr is None else today_arr
    # 数据存储
    dname = os.path.basename(__file__).split('.')[0]
    log_dir = f'result_{dname}'
    if not os.path.exists(log_dir):
        os.makedirs(log_dir)
    csv_path = f'{log_dir}/{today_date}_gen_down_up_by_number.csv'
    rank_number, today_stocks = send_by_number(csv_path, today_date, today_arr, result_dict, indus_count_dict)
    csv_path = f'{log_dir}/{today_date}_gen_down_up_by_date.csv'
    send_by_date(csv_path, today_date, today_stocks, rank_number)


if __name__ == '__main__':
    """
    计算昨日最低价为10日新低，今日涨幅大于3的日期
    """
    stocks = [
        # '黑芝麻'
        # '众生药业'
        # '晨丰科技'
        # '中成股份',
        # '通威股份',
        # '中天科技',
        # '均胜电子',
        # '长江电力',
        # '隆基绿能',
        # '东方电子',
    ]
    # 开始计算
    # todo 设置最大满足条件的点数
    # break_days = 20  # 最多计算20个最低点就结束
    break_days = 5  # 最多计算20个最低点就结束
    start_bkd = 0
    bkd_len = 1
    try:
        arguments = sys.argv[1:]
        if arguments:
            bkd_len = int(arguments[0])
            start_bkd = int(arguments[1]) if len(arguments) == 2 else start_bkd
    except Exception as e:
        start_bkd = 0
        bkd_len = 1
        logger.error(e)
    for bkd in range(start_bkd, start_bkd + bkd_len):
        get_all_stock(stocks, break_days, bkd)
